/**
  **************************************************************************
  * @file     main.c
  * @brief    main program
  **************************************************************************
  *                       Copyright notice & Disclaimer
  *
  * The software Board Support Package (BSP) that is made available to
  * download from Artery official website is the copyrighted work of Artery.
  * Artery authorizes customers to use, copy, and distribute the BSP
  * software and its related documentation for the purpose of design and
  * development in conjunction with Artery microcontrollers. Use of the
  * software is governed by this copyright notice and the following disclaimer.
  *
  * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  *
  **************************************************************************
  */

#include "at32f421_board.h"
#include "at32f421_clock.h"
#include "i2c_application.h"

/** @addtogroup AT32F421_periph_examples
  * @{
  */

/** @addtogroup 421_I2C_communication_dma I2C通信DMA模式示例

  * @{

  */

/** 

  * @brief I2C通信超时时间

  */

#define I2C_TIMEOUT                      0xFFFFFFFF



/** 

  * @brief I2C通信速度和地址

  */

#define I2Cx_SPEED                       100000

#define I2Cx_ADDRESS                     0xA0



/** 

  * @brief I2C端口及相关引脚配置

  */

#define I2Cx_PORT                        I2C1

#define I2Cx_CLK                         CRM_I2C1_PERIPH_CLOCK



#define I2Cx_SCL_PIN                     GPIO_PINS_9

#define I2Cx_SCL_PIN_SOURCE              GPIO_PINS_SOURCE9

#define I2Cx_SCL_PIN_MUX_NUM             GPIO_MUX_4

#define I2Cx_SCL_GPIO_PORT               GPIOA

#define I2Cx_SCL_GPIO_CLK                CRM_GPIOA_PERIPH_CLOCK



#define I2Cx_SDA_PIN                     GPIO_PINS_10

#define I2Cx_SDA_PIN_SOURCE              GPIO_PINS_SOURCE10

#define I2Cx_SDA_PIN_MUX_NUM             GPIO_MUX_4

#define I2Cx_SDA_GPIO_PORT               GPIOA

#define I2Cx_SDA_GPIO_CLK                CRM_GPIOA_PERIPH_CLOCK



/** 

  * @brief I2C DMA配置

  */

#define I2Cx_DMA_CLK                     CRM_DMA1_PERIPH_CLOCK

#define I2Cx_DMA_TX_CHANNEL              DMA1_CHANNEL2

#define I2Cx_DMA_TX_IRQn                 DMA1_Channel3_2_IRQn



#define I2Cx_DMA_RX_CHANNEL              DMA1_CHANNEL3

#define I2Cx_DMA_RX_IRQn                 DMA1_Channel3_2_IRQn



/** 

  * @brief I2C中断配置

  */

#define I2Cx_EVT_IRQn                    I2C1_EVT_IRQn

#define I2Cx_ERR_IRQn                    I2C1_ERR_IRQn



/** 

  * @brief 通信缓冲区大小

  */

#define BUF_SIZE                         8



/** 

  * @brief 主从机模式选择

  */

#define MASTER_BOARD



/** 

  * @brief 发送和接收缓冲区

  */

uint8_t tx_buf[BUF_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

uint8_t rx_buf[BUF_SIZE] = {0};



/** 

  * @brief I2C句柄结构体

  */

i2c_handle_type hi2cx;



/** 

  * @brief 缓冲区比较函数声明

  */

uint32_t buffer_compare(uint8_t* buffer1, uint8_t* buffer2, uint32_t len);



/** 

  * @brief I2C底层初始化函数声明

  */

void i2c_lowlevel_init(i2c_handle_type* hi2c);

/**

  * @brief  错误处理函数

  * @param  error_code 错误代码

  * @retval none

  */

void error_handler(uint32_t error_code)

{

  // 无限循环，LED2闪烁表示错误

  while(1)

  {

    at32_led_toggle(LED2);

    delay_ms(500);

  }

}

/**

  * @brief  比较两个缓冲区的数据是否相等

  * @param  buffer1: 缓冲区1的地址

            buffer2: 缓冲区2的地址

            len:    缓冲区长度

  * @retval 0: 相等

  *         1: 不相等

  */

uint32_t buffer_compare(uint8_t* buffer1, uint8_t* buffer2, uint32_t len)

{

  uint32_t i;



  // 逐字节比较两个缓冲区的数据

  for(i = 0; i < len; i++)

  {

    if(buffer1[i] != buffer2[i])

    {

      return 1; // 发现不相等的字节，返回1

    }

  }



  return 0; // 所有字节都相等，返回0

}

/**

  * @brief  初始化I2C外设所需的底层硬件

  * @param  hi2c I2C句柄指针

  * @retval none

  */

void i2c_lowlevel_init(i2c_handle_type* hi2c)

{

  gpio_init_type gpio_initstructure;



  // 判断是否为指定的I2C端口

  if(hi2c->i2cx == I2Cx_PORT)

  {

    /* 使能I2C及相关GPIO的时钟 */

    crm_periph_clock_enable(I2Cx_CLK, TRUE);

    crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);

    crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);



    /* GPIO配置 */

    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_OPEN_DRAIN;  // 开漏输出

    gpio_initstructure.gpio_pull           = GPIO_PULL_NONE;             // 无上拉/下拉

    gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;           // 复用模式

    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE; // 驱动能力适中



    /* 配置I2C引脚: SCL */

    gpio_initstructure.gpio_pins = I2Cx_SCL_PIN;

    gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_initstructure);

    gpio_pin_mux_config(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN_SOURCE, I2Cx_SCL_PIN_MUX_NUM);



    /* 配置I2C引脚: SDA */

    gpio_initstructure.gpio_pins = I2Cx_SDA_PIN;

    gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_initstructure);

    gpio_pin_mux_config(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN_SOURCE, I2Cx_SDA_PIN_MUX_NUM);



    /* 配置并使能I2C DMA通道中断 */

    nvic_irq_enable(I2Cx_DMA_TX_IRQn, 0, 0);

    nvic_irq_enable(I2Cx_DMA_RX_IRQn, 0, 0);



    /* 配置并使能I2C中断 */

    nvic_irq_enable(I2Cx_EVT_IRQn, 0, 0);

    nvic_irq_enable(I2Cx_ERR_IRQn, 0, 0);



    /* I2C DMA发送和接收通道配置 */

    /* 使能DMA时钟 */

    crm_periph_clock_enable(I2Cx_DMA_CLK, TRUE);



    /* I2C DMA通道配置 */

    hi2c->dma_tx_channel = I2Cx_DMA_TX_CHANNEL;

    hi2c->dma_rx_channel = I2Cx_DMA_RX_CHANNEL;



    dma_reset(hi2c->dma_tx_channel);

    dma_reset(hi2c->dma_rx_channel);



    dma_default_para_init(&hi2c->dma_init_struct);

    hi2c->dma_init_struct.peripheral_inc_enable    = FALSE;                     // 外设地址不递增

    hi2c->dma_init_struct.memory_inc_enable        = TRUE;                      // 存储器地址递增

    hi2c->dma_init_struct.peripheral_data_width    = DMA_PERIPHERAL_DATA_WIDTH_BYTE; // 外设数据宽度为字节

    hi2c->dma_init_struct.memory_data_width        = DMA_MEMORY_DATA_WIDTH_BYTE;     // 存储器数据宽度为字节

    hi2c->dma_init_struct.loop_mode_enable         = FALSE;                     // 不使用循环模式

    hi2c->dma_init_struct.priority                 = DMA_PRIORITY_LOW;          // DMA优先级为低

    hi2c->dma_init_struct.direction                = DMA_DIR_MEMORY_TO_PERIPHERAL; // 传输方向为存储器到外设



    dma_init(hi2c->dma_tx_channel, &hi2c->dma_init_struct);

    dma_init(hi2c->dma_rx_channel, &hi2c->dma_init_struct);



    // 初始化I2C

    i2c_init(hi2c->i2cx, I2C_FSMODE_DUTY_2_1, I2Cx_SPEED);



    // 设置I2C自身的从机地址

    i2c_own_address1_set(hi2c->i2cx, I2C_ADDRESS_MODE_7BIT, I2Cx_ADDRESS);

  }

}

/**

  * @brief  主函数

  * @param  none

  * @retval none

  */

int main(void)

{

  i2c_status_type i2c_status;



  /* 配置NVIC优先级分组 */

  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);



  // 系统时钟配置

  system_clock_config();



  // 开发板初始化

  at32_board_init();



  // 设置I2C端口

  hi2cx.i2cx = I2Cx_PORT;



  // I2C配置

  i2c_config(&hi2cx);



  // 主循环

  while(1)

  {



#if defined (MASTER_BOARD)

    // 主机模式

    

    /* 等待用户按键按下才开始通信 */

    //while(at32_button_press() != USER_BUTTON)

    //{

    //}



    /* 开始发送数据请求 */

    if((i2c_status = i2c_master_transmit_dma(&hi2cx, I2Cx_ADDRESS, tx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    /* 等待通信结束 */

    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    delay_ms(10);



    /* 开始接收数据请求 */

    if((i2c_status = i2c_master_receive_dma(&hi2cx, I2Cx_ADDRESS, rx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    /* 等待通信结束 */

    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    // 比较发送和接收的数据是否一致

    if(buffer_compare(tx_buf, rx_buf, BUF_SIZE) == 0)

    {

      at32_led_on(LED3); // 数据一致，LED3点亮

    }

    else

    {

      error_handler(i2c_status); // 数据不一致，进入错误处理

    }



#else

    // 从机模式

    

    /* 等待用户按键按下才开始通信 */

    while(at32_button_press() != USER_BUTTON)

    {

    }



    /* 开始接收数据过程 */

    if((i2c_status = i2c_slave_receive_dma(&hi2cx, rx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    /* 等待通信结束 */

    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    /* 开始发送数据过程 */

    if((i2c_status = i2c_slave_transmit_dma(&hi2cx, tx_buf, BUF_SIZE, I2C_TIMEOUT)) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    /* 等待通信结束 */

    if(i2c_wait_end(&hi2cx, I2C_TIMEOUT) != I2C_OK)

    {

      error_handler(i2c_status);

    }



    // 比较发送和接收的数据是否一致

    if(buffer_compare(tx_buf, rx_buf, BUF_SIZE) == 0)

    {

      at32_led_on(LED3); // 数据一致，LED3点亮

    }

    else

    {

      error_handler(i2c_status); // 数据不一致，进入错误处理

    }



#endif



  }

}

/**
  * @}
  */

/**
  * @}
  */
